package com.yuntsg.subject_database.servic;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.alibaba.fastjson.JSONObject;
import com.yuntsg.subject_database.component.SubjectDatabaseComponent;
import com.yuntsg.subject_database.entity.CorePaperUniteEntity;
import com.yuntsg.subject_database.entity.IndexConfig;
import com.yuntsg.subject_database.entity.PublicEntity;
import com.yuntsg.subject_database.util.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import static com.yuntsg.subject_database.servic.AllQueryBasicService.allQuery;
import static com.yuntsg.subject_database.servic.AllQueryBasicService.coventList;
import static com.yuntsg.subject_database.servic.SubjectDatabaseUnit.DelOtherLower;
import static java.util.stream.Collectors.toList;

@Service
@Slf4j
public class SubjectDatabaseService {

//    @Resource
//    ElasticsearchTemplate<CorePaperUnite, String> corePaperUnite30w;

    @Resource
    SubjectDatabaseComponent subDataComponent;

    public static Map<Integer, SubjectDatabaseWord.ArticleInfo> getDataListByYear(Map<Integer, SubjectDatabaseWord.ArticleInfo> param, Integer year) {
        Map<Integer, SubjectDatabaseWord.ArticleInfo> res = new ConcurrentHashMap<>();
        param.forEach((k, v) -> {
            Integer pubYear = v.getPubYear();
            if (pubYear.equals(year)) {
                res.put(k, v);
            }
        });
        return res;
    }

    public static Map<Integer, SubjectDatabaseWord.ArticleInfo> getDataListByYearAll(Map<Integer, SubjectDatabaseWord.ArticleInfo> param, int year) {
        Map<Integer, SubjectDatabaseWord.ArticleInfo> res = new ConcurrentHashMap<>();
        param.forEach((k, v) -> {
            int pubYear = v.getPubYear();
            if (pubYear <= year) {
                res.put(k, v);
            }
        });
        return res;
    }

    // 本接口是首页，仅返回很少的数据，单位或作者的排行传导给单位或作者的篇数及得分。
    public Object authSearch(PublicEntity.SearchEntity searchEntity) throws Exception {
        Map<String, Object> res = new HashMap<>();
        if (!StringUtils.isEmpty(searchEntity.getRekey())) {
            Object object = RedisUtil.getObject(searchEntity.getRekey());
            if (object != null) {
                Map<String, PublicEntity.TypeAndRank> unitOrAuthAndRankMap = (Map<String, PublicEntity.TypeAndRank>) RedisUtil.getObject(searchEntity.getRekey());
                SmallTool.printMess("个人检索开始");
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                boolean isInsertTable = false; // 是否对结果进行插表，true是插表。
                String saveTable = subDataComponent.getSaveTable();
                String uniteTable = subDataComponent.getUniteTable();

                List<PublicEntity.TableField> tableList = Collections.synchronizedList(new ArrayList<>());
                Map<String, Map<String, List<SubjectDatabaseUnit.NsfcInfo>>> nsfcInfoMap = subDataComponent.getNsfcInfoMap();
                Map<String, Map<String, PublicEntity.TopLower>> ruleMap = subDataComponent.getRuleMap();

                Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap = readArticleInfo(doSearchEntity(searchEntity), uniteTable);
                System.out.println(format.format(new Date()) + " ③ 读表结束，Map总条数：" + allArticleInfoMap.size());
                SubjectDatabaseUnit.readAuthTable(saveTable, allArticleInfoMap, nsfcInfoMap, ruleMap, unitOrAuthAndRankMap, tableList, isInsertTable);
                System.out.println(format.format(new Date()) + " ④ 计算完成，插表总条数：" + tableList.size());
                res.put("data", tableList);
                res.put("rank", unitOrAuthAndRankMap);
                return res;
            } else {
                return res;

            }


        } else {
            return res;
        }


    }

    // 本接口是首页，仅返回很少的数据，单位或作者的排行传导给单位或作者的篇数及得分。
    public Object unitSearch(PublicEntity.SearchEntity searchEntity) throws Exception {
        Map<String, Object> res = new HashMap<>();
        if (!StringUtils.isEmpty(searchEntity.getRekey())) {
            Object object = RedisUtil.getObject(searchEntity.getRekey());
            if (object != null) {
                Map<String, PublicEntity.TypeAndRank> unitOrAuthAndRankMap = (Map<String, PublicEntity.TypeAndRank>) RedisUtil.getObject(searchEntity.getRekey());
                SmallTool.printMess("单位检索开始");
                if (unitOrAuthAndRankMap == null) {
                    return "";
                }
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                boolean isInsertTable = false; // 是否对结果进行插表，true是插表。
                String saveTable = subDataComponent.getSaveTable();
                String uniteTable = subDataComponent.getUniteTable();

                List<PublicEntity.TableField> tableList = Collections.synchronizedList(new ArrayList<>());
                Map<String, Map<String, List<SubjectDatabaseUnit.NsfcInfo>>> nsfcInfoMap = subDataComponent.getNsfcInfoMap();
                Map<String, Map<String, PublicEntity.TopLower>> ruleMap = subDataComponent.getRuleMap();

                Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap = readArticleInfo(doSearchEntity(searchEntity), uniteTable);
                System.out.println(format.format(new Date()) + " ③ 读表结束，Map总条数：" + allArticleInfoMap.size());
                SubjectDatabaseUnit.readUnivTable(saveTable, allArticleInfoMap, nsfcInfoMap, ruleMap, unitOrAuthAndRankMap, tableList, isInsertTable);
                System.out.println(format.format(new Date()) + " ④ 计算完成，插表总条数：" + tableList.size());
                res.put("data", tableList);
                res.put("rank", unitOrAuthAndRankMap);
                return res;
            } else {
                return res;
            }
        } else {
            return res;
        }


    }

    // 本接口pm专用。
    public Object unitSearchPm(PublicEntity.SearchEntity searchEntity) throws Exception {
        Map<String, Object> res = new HashMap<>();
        if (!StringUtils.isEmpty(searchEntity.getRekey())) {
            Object object = RedisUtil.getObject(searchEntity.getRekey());
            if (object != null) {
                Map<String, PublicEntity.TypeAndRank> unitOrAuthAndRankMap = (Map<String, PublicEntity.TypeAndRank>) RedisUtil.getObject(searchEntity.getRekey());
                SmallTool.printMess("单位检索开始");
                if (unitOrAuthAndRankMap == null) {
                    return "";
                }
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                boolean isInsertTable = false; // 是否对结果进行插表，true是插表。
                String saveTable = subDataComponent.getSaveTable();
                String uniteTable = subDataComponent.getUniteTable();

                List<PublicEntity.TableField> tableList = Collections.synchronizedList(new ArrayList<>());
                Map<String, Map<String, List<SubjectDatabaseUnit.NsfcInfo>>> nsfcInfoMap = subDataComponent.getNsfcInfoMap();
                Map<String, Map<String, PublicEntity.TopLower>> ruleMap = subDataComponent.getRuleMap();

//                Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap = readArticleInfo(doSearchEntity(searchEntity), uniteTable);
                Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap = readArticleInfoPm(doSearchEntityPm(searchEntity), uniteTable);
                System.out.println(format.format(new Date()) + " ③ 读表结束，Map总条数：" + allArticleInfoMap.size());
                SubjectDatabaseUnit.readUnivTable(saveTable, allArticleInfoMap, nsfcInfoMap, ruleMap, unitOrAuthAndRankMap, tableList, isInsertTable);
                System.out.println(format.format(new Date()) + " ④ 计算完成，插表总条数：" + tableList.size());
                res.put("data", tableList);
                res.put("rank", unitOrAuthAndRankMap);
                return res;
            } else {
                return res;
            }
        } else {
            return res;
        }


    }

    // 本接口是首页，仅返回很少的数据，单位或作者的排行传导给单位或作者的篇数及得分。
    public Object homeSearch(PublicEntity.SearchEntity searchEntity) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Map<String, PublicEntity.TypeAndRank> unitOrAuthAndRankMap = new ConcurrentHashMap<>();
        String specialist = searchEntity.getSpecialist();
        String code = searchEntity.getCode();
        Map<String, SubjectDatabaseWord.RankScore> rankScore = null;
        if (specialist.startsWith("期刊名称==")) {
            rankScore = subDataComponent.getRankScoreMap().get("journal");
        } else {
            rankScore = subDataComponent.getRankScoreMap().get(specialist);
        }
        int top = 100;
        boolean isInsertTable = false; // 是否对结果进行插表，true是插表。
        boolean isCoWord = false; // 是否计算共词，true是计算。
        int jid = 0;
        String saveTable = subDataComponent.getSaveTable();
        String uniteTable = subDataComponent.getUniteTable();
        // pm处理?
        boolean isPm = false;

        double startYear = (Calendar.getInstance().get(Calendar.YEAR) + ((Calendar.getInstance().get(Calendar.MONTH) + 1) * 0.083)) - 6;
        List<PublicEntity.TableField> tableList = Collections.synchronizedList(new ArrayList<>());
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap = readArticleInfo(doSearchEntity(searchEntity), uniteTable);
        System.out.println(format.format(new Date()) + " ③ 读表结束，Map总条数：" + allArticleInfoMap.size());
        SubjectDatabaseWord.wordOut(isPm, saveTable, rankScore, startYear, top, code, specialist, jid, null, allArticleInfoMap, unitOrAuthAndRankMap, tableList, isInsertTable, isCoWord);

        System.out.println(format.format(new Date()) + " ④ 计算完成，插表总条数：" + tableList.size());
        Map<String, Object> res = new HashMap<>();
        res.put("data", tableList);
        // rank 存在redis去
        String reKey = Code.digestData(System.currentTimeMillis() + "reKeyDIS");
        RedisUtil.saveObject(reKey, unitOrAuthAndRankMap);
        res.put("rank", unitOrAuthAndRankMap);
        res.put("rekey", reKey);
        return res;
    }

    // 本接口是首页，仅返回很少的数据，单位或作者的排行传导给单位或作者的篇数及得分。 --pm专用
    public Object homeSearchPm(PublicEntity.SearchEntity searchEntity) throws Exception {
        // pm传递一堆pmid进来 进行分析 主要用于改造研究漂移用的
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 全部
        Map<String, PublicEntity.TypeAndRank> unitOrAuthAndRankMap = new ConcurrentHashMap<>();
        // 近三年
        log.info("要查询的数量+" + searchEntity.getPmids().size());
        Map<String, PublicEntity.TypeAndRank> unitOrAuthAndRankMap1 = new ConcurrentHashMap<>();
        Map<String, PublicEntity.TypeAndRank> unitOrAuthAndRankMap2 = new ConcurrentHashMap<>();
        Map<String, PublicEntity.TypeAndRank> unitOrAuthAndRankMap3 = new ConcurrentHashMap<>();
        String specialist = searchEntity.getSpecialist();
        String code = searchEntity.getCode();
        Map<String, SubjectDatabaseWord.RankScore> rankScore = subDataComponent.getRankScoreMap().get("journal");
        int top = 100;
        boolean isInsertTable = false; // 是否对结果进行插表，true是插表。
        boolean isCoWord = true; // 是否计算共词，true是计算。
        int jid = 0;
        String saveTable = subDataComponent.getSaveTable();
        String uniteTable = subDataComponent.getUniteTable();

        List<PublicEntity.TableField> tableListAll = Collections.synchronizedList(new ArrayList<>());


        //需要分出近三年的数据才可以 目前返回的是全部数据的

        // 最近三年数据
        int i = DateUtil.year(new Date());

        int year1 = i - 1; //2021
        int year2 = i - 2; // 2020
        int year3 = i - 3; // 2019
        // 近三年
        List<PublicEntity.TableField> tableListAll1 = Collections.synchronizedList(new ArrayList<>());
        List<PublicEntity.TableField> tableListAll2 = Collections.synchronizedList(new ArrayList<>());
        List<PublicEntity.TableField> tableListAll3 = Collections.synchronizedList(new ArrayList<>());

        int i1 = Calendar.getInstance().get(Calendar.YEAR);
        double startYearAll = (i1 + ((Calendar.getInstance().get(Calendar.MONTH) + 1) * 0.083)) - 6;
        double startYearAll1 = (year1 + ((Calendar.getInstance().get(Calendar.MONTH) + 1) * 0.083)) - 6;
        double startYearAll2 = (year2 + ((Calendar.getInstance().get(Calendar.MONTH) + 1) * 0.083)) - 6;
        double startYearAll3 = (year3 + ((Calendar.getInstance().get(Calendar.MONTH) + 1) * 0.083)) - 6;


        // key 是pmid
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap = readArticleInfoPm(doSearchEntityPm(searchEntity), uniteTable);
        // 获取特定年数据
        log.info("查询到的数量是++" + allArticleInfoMap.size()); // 全部年份数量.
        // 最近三年的新词 计算步骤 假如这批数据是2018,2019,2020,2021,2022 原来是 计算的全部 当前年-6 再加5 相当于减1 最近三年是 可以认为  2021.581, 2020.581, 2019.581,
        // 那么 最近三年每年新词 应该是拿当前年的词 集合不在当前年以前所有词集合里面 也就是说 我如果拿2020年新词 我需要把2020年词集合 和2020之前词集合作对比 取差集 才是2020的新词
        // pm处理? 需要处理最近三年的词和以没有的
        boolean isPm = true;
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap1 = getDataListByYear(allArticleInfoMap, year1);
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap2 = getDataListByYear(allArticleInfoMap, year2);
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap3 = getDataListByYear(allArticleInfoMap, year3);
        System.out.println(format.format(new Date()) + " ③ 读表结束，全部文章数量：" + allArticleInfoMap.size());
        System.out.println(format.format(new Date()) + year1 + "年全部文章数量：" + allArticleInfoMap1.size());
        System.out.println(format.format(new Date()) + year2 + "年全部文章数量：" + allArticleInfoMap2.size());
        System.out.println(format.format(new Date()) + year3 + "年全部文章数量：" + allArticleInfoMap3.size());
        // 需要拿到当前年去年以前的文章全部文章
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap1All = getDataListByYearAll(allArticleInfoMap, year1 - 1);
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap2All = getDataListByYearAll(allArticleInfoMap, year2 - 1);
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap3All = getDataListByYearAll(allArticleInfoMap, year3 - 1);
        //最近三年前之前文章
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap4All = getDataListByYearAll(allArticleInfoMap, year3 - 2);
        SmallTool.printMess(year1 - 1 + "之前全部文章数量" + allArticleInfoMap1All.size());
        SmallTool.printMess(year2 - 1 + "之前全部文章数量" + allArticleInfoMap2All.size());
        SmallTool.printMess(year3 - 1 + "之前全部文章数量" + allArticleInfoMap3All.size());
        SmallTool.printMess(year3 - 2 + "之前全部文章数量" + allArticleInfoMap3All.size());
        //分开计算 提高速度
        if (StrUtil.isEmpty(searchEntity.getParamYear())) {
            SubjectDatabaseWord.wordOut(isPm, saveTable, rankScore, startYearAll, top, code, specialist, jid, allArticleInfoMap4All, allArticleInfoMap, unitOrAuthAndRankMap, tableListAll, isInsertTable, isCoWord);
        } else if (searchEntity.getParamYear().equals(String.valueOf(year1))) {
            SubjectDatabaseWord.wordOut(isPm, saveTable, rankScore, startYearAll1, top, code, specialist, jid, allArticleInfoMap1All, allArticleInfoMap1, unitOrAuthAndRankMap1, tableListAll1, isInsertTable, isCoWord);
        } else if (searchEntity.getParamYear().equals(String.valueOf(year2))) {
            SubjectDatabaseWord.wordOut(isPm, saveTable, rankScore, startYearAll2, top, code, specialist, jid, allArticleInfoMap2All, allArticleInfoMap2, unitOrAuthAndRankMap2, tableListAll2, isInsertTable, isCoWord);
        } else if (searchEntity.getParamYear().equals(String.valueOf(year3))) {
            SubjectDatabaseWord.wordOut(isPm, saveTable, rankScore, startYearAll3, top, code, specialist, jid, allArticleInfoMap3All, allArticleInfoMap3, unitOrAuthAndRankMap3, tableListAll3, isInsertTable, isCoWord);
        }

        System.out.println(format.format(new Date()) + " ④ 计算完成，插表总条数：" + tableListAll.size());
        Map<String, Object> res = new HashMap<>();
        res.put("data", tableListAll);
        res.put("data1", tableListAll1);
        res.put("data2", tableListAll2);
        res.put("data3", tableListAll3);
        // rank 存在redis去
        String reKey = Code.digestData(System.currentTimeMillis() + "reKeyDIS");
        RedisUtil.saveObject(reKey, unitOrAuthAndRankMap);
        res.put("rank", unitOrAuthAndRankMap);
        res.put("rekey", reKey);
        return res;
    }

    // pm专用检索
    public List<CorePaperUniteEntity> doSearchEntityPm(PublicEntity.SearchEntity searchEntity) throws Exception {
        BoolQuery.Builder queryBuilder = new BoolQuery.Builder();
        ElasticsearchClient client = EsClient.client();
//        queryBuilder.must(QueryBuilders.termsQuery("pmid", searchEntity.getPmids()));
//        queryBuilder.must(QueryBuilders.termQuery("dataname", "NCBI"));
        List<String> pmids = searchEntity.getPmids();
        List<FieldValue> values = new ArrayList<>();
        for (String id : pmids) {
            values.add(FieldValue.of(id));
        }
        queryBuilder.must(TermsQuery.of(t -> t.field("pmid").terms(new TermsQueryField.Builder()
                .value(values).build()
        ))._toQuery());

        queryBuilder.must(TermQuery.of(i -> i.field("pmid").value("NCBI"))._toQuery());
        // 分页、高亮、排序等设置部分
//        PageSortHighLight psh = new PageSortHighLight(1, 10000);
//        Attach attach = new Attach();
//        attach.setIncludes(new String[]{"id"});
//        attach.setPageSortHighLight(psh);

        List<Hit<CorePaperUniteEntity>> hits = allQuery(IndexConfig.ARTICLE_INDEX, queryBuilder.build()._toQuery(), 0, 10000, null, CorePaperUniteEntity.class);
//        if (hits == null || hits.size() == 0) {
//            return new ResultBean<>("查询不到该作者信息");
//        }
        // log.info("检索结果长度为___" + pageList.getTotalElements());
        List<CorePaperUniteEntity> search = coventList(hits);

//        PageList<CorePaperUniteEntity> search = client.search(queryBuilder, CorePaperUniteEntity.class);
//        List<CorePaperUnite> list = search.getList();
//        return corePaperUnite30w.search(queryBuilder,attach, CorePaperUnite.class);
        return search;
    }

    @SneakyThrows
    public List<CorePaperUniteEntity> doSearchEntity(PublicEntity.SearchEntity searchEntity)  {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(format.format(new Date()) + " ① searchEntity：" + searchEntity);
        System.out.println(searchEntity);
        Map<String, PublicEntity.TopLower> deptRuleMap = subDataComponent.getRuleMap().get("dept");
        BoolQuery.Builder queryBuilder = new BoolQuery.Builder();
        if (searchEntity.getCode().equals("基于期刊学科")) {
            // 经测试使用期刊list或者使用for，结果是一样的。另外，for时使用数字的jid和文本的jid结果也是一样的。
            List<String> jourids = searchEntity.getJourids();
            List<FieldValue> values = new ArrayList<>();
            for (String id : jourids) {
                values.add(FieldValue.of(id));
            }
            queryBuilder.should(TermsQuery.of(t -> t.field("jid").terms(new TermsQueryField.Builder()
                    .value(values).build()
            ))._toQuery());
        }
        if (searchEntity.getCode().equals("基于pmid")) {
            // 经测试使用期刊list或者使用for，结果是一样的。另外，for时使用数字的jid和文本的jid结果也是一样的。
//            queryBuilder.should(QueryBuilders.termsQuery("jid", searchEntity.getPmids()));
        }
        if (searchEntity.getCode().equals("基于作者部门")) {

            for (String ad : searchEntity.getAds()) {
                if (deptRuleMap!=null&&deptRuleMap.containsKey(ad)) {
                    Query query = MultiMatchQuery.of(t -> t.fields("cndept","endept").query(deptRuleMap.get(ad).getTop()).minimumShouldMatch("100%"))._toQuery();
                    queryBuilder.should(query);
                }
                Query query = MultiMatchQuery.of(t -> t.fields("cnad","enad").query(ad).minimumShouldMatch("100%"))._toQuery();
                queryBuilder.should(query);
            }
        }
        List<Hit<CorePaperUniteEntity>> hits = allQuery(IndexConfig.ARTICLE_INDEX, queryBuilder.build()._toQuery(), 0, 10000, null, CorePaperUniteEntity.class);
        List<CorePaperUniteEntity> search = coventList(hits);
        return search;
    }

    // 这个是执行插表的程序。
    public List<Integer> insertTableSearch(@RequestBody PublicEntity.SearchEntity searchEntity) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String specialist = searchEntity.getSpecialist();
        String code = searchEntity.getCode();
        Map<String, SubjectDatabaseWord.RankScore> rankScore = null;
        if (specialist.startsWith("期刊名称==")) {
            rankScore = subDataComponent.getRankScoreMap().get("journal");
        } else {
            rankScore = subDataComponent.getRankScoreMap().get(specialist);
        }
        int top = 100;
        boolean isInsertTable = true; // 是否对结果进行插表，true是插表。
        boolean isCoWord = true; // 是否计算共词，true是计算。
        int jid = 0;
        String saveTable = subDataComponent.getSaveTable();
        Map<String, Map<String, List<SubjectDatabaseUnit.NsfcInfo>>> nsfcInfoMap = subDataComponent.getNsfcInfoMap();
        Map<String, Map<String, PublicEntity.TopLower>> ruleMap = subDataComponent.getRuleMap();
        String uniteTable = subDataComponent.getUniteTable();

        double startYear = (Calendar.getInstance().get(Calendar.YEAR) + ((Calendar.getInstance().get(Calendar.MONTH) + 1) * 0.083)) - 6;
        List<PublicEntity.TableField> tableList = Collections.synchronizedList(new ArrayList<>());
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap = readArticleInfo(doSearchEntity(searchEntity), uniteTable);
        System.out.println(format.format(new Date()) + " ③ 读表结束，Map总条数：" + allArticleInfoMap.size());

        Map<String, PublicEntity.TypeAndRank> unitOrAuthAndRankMap = new ConcurrentHashMap<>();// 单位或作者的排行传导给单位或作者的篇数及得分。
        try {
            SubjectDatabaseWord.wordOut(false, saveTable, rankScore, startYear, top, code, specialist, jid, null, allArticleInfoMap, unitOrAuthAndRankMap, tableList, isInsertTable, isCoWord);
            SubjectDatabaseUnit.readUnivTable(saveTable, allArticleInfoMap, nsfcInfoMap, ruleMap, unitOrAuthAndRankMap, tableList, isInsertTable);
            SubjectDatabaseUnit.readAuthTable(saveTable, allArticleInfoMap, nsfcInfoMap, ruleMap, unitOrAuthAndRankMap, tableList, isInsertTable);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        System.out.println(format.format(new Date()) + " ④ 计算完成，插表总条数：" + tableList.size());
        return new ArrayList<>();
    }

    public Map<Integer, SubjectDatabaseWord.ArticleInfo> readArticleInfoPm(List<CorePaperUniteEntity> search, String uniteTable) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap = new ConcurrentHashMap<>();
        List<Integer> list = new ArrayList<>();
        for (CorePaperUniteEntity corePaperUnite : search) {
            Integer id = corePaperUnite.getId();
            list.add(id);
        }
        SmallTool.printMess("es返回需要查询的数量++" + search.size());
        List<List<Integer>> lists = ListUtil.split(list, 1000);
//        String select = "id`,`article_id`,`data_info`,`data_unique`,`altmetric`,`citation_num`,`citation_quota`,`cn_auth_list`,`cn_kw_list`,`en_auth_list`,`en_kw_map`,`fund_list`,`is_beida`,`is_cscd`,`is_pubmed`,`is_tongjiyuan`,`is_zhong_hua`,`is_zky`,`pub_date`,`pub_year`,`reference_quota`,`scie_if`,`unit_list`,`zky_dalei";
        System.out.println(format.format(new Date()) + " ② 读表开始，论文总条数：" + list.size());
        lists.parallelStream().forEach(idList -> {
            try {
                List<Entity> tableData = Db.use().query("select  *   from " + uniteTable + " where id in (" + CollUtil.join(idList, ",") + ")");
                for (Entity entry : tableData) {
                    getArticleInfoPm(entry, OftenUtils.getNowYear(), allArticleInfoMap);
                }
            } catch (Exception throwables) {
                throwables.printStackTrace();
            }
        });
        return allArticleInfoMap;
    }

    public Map<Integer, SubjectDatabaseWord.ArticleInfo> readArticleInfo(List<CorePaperUniteEntity> search, String uniteTable) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap = new ConcurrentHashMap<>();
        List<Integer> list = new ArrayList<>();
        for (CorePaperUniteEntity corePaperUnite : search) {
            Integer id = corePaperUnite.getId();
            list.add(id);
        }
        List<List<Integer>> lists = ListUtil.split(list, 1000);
        String select = "id`,`article_id`,`data_info`,`altmetric`,`citation_num`,`citation_quota`,`cn_auth_list`,`cn_kw_list`,`en_auth_list`,`en_kw_map`,`fund_list`,`is_beida`,`is_cscd`,`is_pubmed`,`is_tongjiyuan`,`is_zhong_hua`,`is_zky`,`pub_date`,`pub_year`,`reference_quota`,`scie_if`,`unit_list`,`zky_dalei";
        System.out.println(format.format(new Date()) + " ② 读表开始，论文总条数：" + list.size());
        lists.parallelStream().forEach(idList -> {
            try {
                List<Entity> tableData = Db.use().query("select `" + select + "` from " + uniteTable + " where id in (" + CollUtil.join(idList, ",") + ")");
                for (Entity entry : tableData) {
                    getArticleInfo(entry, OftenUtils.getNowYear(), allArticleInfoMap);
                }
            } catch (Exception throwables) {
                throwables.printStackTrace();
            }
        });
        return allArticleInfoMap;
    }

    // 获取论文信息。得分的计算方法考虑了出版时间，影响因子，中科院的分区，被引次数等。其中，被引次数根据出版时间得到不等的系数，出版时间越老，系数越小，但只要有被引次数，最小的系数为1，没有被引次数的，均为0.25。只要2005年以来的数据。
    public void getArticleInfo(Entity entry, Integer nowYear, Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap) {
        int aId = OftenUtils.getIntField(entry, "article_id");
        int pubYear = OftenUtils.strToInteger(OftenUtils.getStrField(entry, "pub_year"));
        if (aId > 0 && pubYear > 2005) {
            SubjectDatabaseWord.ArticleInfo articleInfo = new SubjectDatabaseWord.ArticleInfo();
            articleInfo.setAId(aId);
            articleInfo.setZkySmall(OftenUtils.strToList(OftenUtils.getStrField(entry, "zky_xiao_lei")));
            articleInfo.setBeiDaDaLei(OftenUtils.getStrField(entry, "beida_dalei"));
            articleInfo.setBeiDaXiaoLei(OftenUtils.getStrField(entry, "beida_xiao_lei"));
            articleInfo.setPubMedSubject(OftenUtils.strToList(OftenUtils.getStrField(entry, "pubmed_subject")));
            int jId = OftenUtils.getIntField(entry, "jour_id");
            articleInfo.setJid(jId);
            articleInfo.setEnKwMap(OftenUtils.strToMap(OftenUtils.getStrField(entry, "en_kw_map")));
            articleInfo.setCnKwList(OftenUtils.strToList(OftenUtils.getStrField(entry, "cn_kw_list")));
            int zhongHua = OftenUtils.getIntField(entry, "is_zhong_hua");
            int beiDa = OftenUtils.getIntField(entry, "is_beida");
            int tongJiYuan = OftenUtils.getIntField(entry, "is_tongjiyuan");
            int cscd = OftenUtils.getIntField(entry, "is_cscd");
            int zky = OftenUtils.getIntField(entry, "is_zky");
            int pubMed = OftenUtils.getIntField(entry, "is_pubmed");
            int sixJ = OftenUtils.getIntField(entry, "is_six_j");
            int cite = OftenUtils.getIntField(entry, "is_cite");
            articleInfo.setIsSixJ(sixJ);
            articleInfo.setIsZHua(zhongHua);
            articleInfo.setIsBeida(beiDa);
            articleInfo.setIsTongJiYuan(tongJiYuan);
            articleInfo.setIsCscd(cscd);
            articleInfo.setIsPubmed(pubMed);
            articleInfo.setIsCite(cite);
            articleInfo.setIsZky(zky);
            int zkyDaLeiInt = 6;
            int zky_dalei = OftenUtils.getIntField(entry, "zky_dalei");
            if (zky_dalei > 0) {
                zkyDaLeiInt = zky_dalei;
            } else {
                if ((zhongHua + beiDa + tongJiYuan + cscd + zky + pubMed + sixJ + cite) > 0) {
                    zkyDaLeiInt = 5;
                }
            }
            articleInfo.setZkyDaleiInt(zkyDaLeiInt);
            articleInfo.setZkySubject(OftenUtils.strToList(OftenUtils.getStrField(entry, "zky_subject")));

            articleInfo.setPubYear(pubYear);
            if (pubYear < 2010) {
                pubYear = 2010;
            }
            double pubTime = pubYear + PublicUtils.getDateScore(OftenUtils.getStrField(entry, "pub_date"));
            int tc = OftenUtils.getIntField(entry, "citation_num");
            articleInfo.setTimeCited(tc);
            double citeScore = OftenUtils.getDouField(entry, "cite_score");
            if (citeScore < 0.01) {
                citeScore = 0.01;
            }
            double score = OftenUtils.Arith.div((OftenUtils.Arith.div((pubTime - 2009), 11) * citeScore), zkyDaLeiInt);
            double ratio = 0.25; // 系数
            if (tc > 0) {
                int yearNum = nowYear - pubYear;
                if (yearNum < 2) {
                    ratio = OftenUtils.Arith.div(tc, 1);
                }
                if (yearNum == 2) {
                    ratio = OftenUtils.Arith.div(tc, 2);
                }
                if (yearNum == 3) {
                    ratio = OftenUtils.Arith.div(tc, 3);
                }
                if (yearNum == 4) {
                    ratio = OftenUtils.Arith.div(tc, 4);
                }
                if (yearNum == 5 || yearNum == 6) {
                    ratio = OftenUtils.Arith.div(tc, 5);
                }
                if (yearNum > 6 && yearNum < 10) {
                    ratio = OftenUtils.Arith.div(tc, 6);
                }
                if (yearNum > 9) {
                    ratio = OftenUtils.Arith.div(tc, 10);
                }
                if (ratio < 1.0) {
                    ratio = 1.0;
                }
            }
            score = score * ratio;
            articleInfo.setScore(score);

            Set<String> firstAuthSet = new HashSet<>();
            firstAuth(OftenUtils.getStrField(entry, "first_en_au"), firstAuthSet);
            firstAuth(OftenUtils.getStrField(entry, "first_cn_au"), firstAuthSet);
            articleInfo.setFirstAuthSet(firstAuthSet);

            Set<String> corrAuthSet = new HashSet<>();
            firstAuth(OftenUtils.getStrField(entry, "first_corr"), corrAuthSet);
            firstAuth(OftenUtils.getStrField(entry, "corr_auth"), corrAuthSet);
            articleInfo.setCorrAuthSet(corrAuthSet);

            articleInfo.setFundList(PublicUtils.getFundList(OftenUtils.getStrField(entry, "fund_list")));

            // 下面为因合并而新添加的字段：
            double zkyDaLeiDou = zky_dalei + 0.0;
            if (zkyDaLeiDou == 2.0) {
                zkyDaLeiDou = 0.5;
            }
            if (zkyDaLeiDou == 3.0) {
                zkyDaLeiDou = 0.33;
            }
            if (zkyDaLeiDou == 4.0) {
                zkyDaLeiDou = 0.25;
            }
            if (zkyDaLeiDou < 0.1) {
                if ((zhongHua + beiDa + tongJiYuan + cscd + zky + pubMed) > 0) {
                    zkyDaLeiDou = 0.2;
                }
            }
            articleInfo.setZkyDaLeiDou(zkyDaLeiDou);

            String unit = OftenUtils.getStrField(entry, "unit_list");
            if (SubjectDatabaseWord.isChina(unit)) {
                articleInfo.setIsChina(1);
            }
            List<String> unitList = OftenUtils.strToList(unit);
            articleInfo.setUnitList(unitList);
            articleInfo.setPubTime(pubTime);
            articleInfo.setEnAuthList(OftenUtils.strToList(OftenUtils.getStrField(entry, "en_auth_list")));
            articleInfo.setCnAuthList(OftenUtils.strToList(OftenUtils.getStrField(entry, "cn_auth_list")));
            articleInfo.setAltmetric(OftenUtils.getDouField(entry, "altmetric"));
            articleInfo.setScieIf(OftenUtils.getDouField(entry, "scie_if"));
            articleInfo.setCitationQuota(OftenUtils.getDouField(entry, "citation_quota"));
            articleInfo.setReferenceQuota(OftenUtils.getDouField(entry, "reference_quota"));
            articleInfo.setDeptList(PublicUtils.getDeptList(OftenUtils.getStrField(entry, "dept_list")));
            List<SubjectDatabaseWord.DataInfo> dataInfoList = JSONObject.parseArray(OftenUtils.getStrField(entry, "data_info"), SubjectDatabaseWord.DataInfo.class);
            articleInfo.setDataInfoList(dataInfoList);
            allArticleInfoMap.put(aId, articleInfo);
        }
    }


    public static void firstAuthUnit(String auth, Set<String> set) {
        // 预处理作者信息
        String s = reAuStand(auth);
        auth = s.replace("!@#", ";");
        // 处理完毕
        String[] split = auth.split(";");
        for (String s1 : split) {
            if (s1.length() > 1) {
                String s11 = authorBlankSpace(reName(s1));
                String s2 = DelOtherLower(reName(s11));
                set.add(s2);
            }
        }
    }

    // 获取真是作者信息
    public static void firstRealAuth(String auth, Set<String> set) {

        // 预处理作者信息
        String s = reAuStand(auth);
        auth = s.replace("!@#", ";");
        // 处理完毕
        String[] split = auth.split(";");
        T:
        for (String s1 : split) {
            if (s1.length() > 1) {
                String s11 = authorBlankSpace(reName(s1));
                String s2 = DelOtherLower((s11));
                set.add(s2);
                break T;
            }


        }

    }

    // 去作者的空格，统一的标准。
    public static String authorBlankSpace(String auth) {
        return auth.replace("\uE3C7", "").replace("\uE492", "").replace("\uE3A3", "").replace("\uE1DD", "").replace("\uE09C", "").replace("\uE0B0", "").replace("-", "").replace(",", "").replace(".", "").replaceAll(" +", "").replace("  ", "").replace(" ", "").toLowerCase().trim();
    }

    //规范作者名字，将多个空格规范为一个，逗号前的、后的，以及点前的、后的等，给予删除。如果以点结尾，也给予删除。
    public static String reName(String name) {
        String str = name.replace("0̄", "o")
                .replace("¹", "1")
                .replace("①", "1")
                .replace("⒈", "1")
                .replace("²", "2")
                .replace("⒉", "2")
                .replace("³", "3")
                .replace("⒊", "3")
                .replace("⑤", "5")
                .replace("ʼ", "'")
                .replace("－", "-")
                .replace("−", "-")
                .replace("⁻", "-")
                .replace("‐", "-")
                .replace("‑", "-")
                .replace("⁃", "-")
                .replace("‒", "-")
                .replace("–", "-")
                .replace("—", "-")
                .replace("―", "-")
                .replace("！", "!")
                .replace("﹟", "#")
                .replace("＃", "#")
                .replace("♯", "#")
                .replace("＄", "$")
                .replace("﹠", "&")
                .replace("＆", "&")
                .replace("（", "(")
                .replace("⟨", "(")
                .replace("）", ")")
                .replace("⟩", ")")
                .replace("⁎", "*")
                .replace("＊", "*")
                .replace("，", ",")
                .replace("﹒", ".")
                .replace("．", ".")
                .replace("。", ".")
                .replace("∙", ".")
                .replace("／", "/")
                .replace("⁄", "/")
                .replace("∕", "/")
                .replace("⧸", "/")
                .replace("：", ":")
                .replace("；", ";")
                .replace("＠", "@")
                .replace("［", "[")
                .replace("【", "[")
                .replace("﹝", "[")
                .replace("〔", "[")
                .replace("〖", "[")
                .replace("＼", "\\")
                .replace("⧹", "\\")
                .replace("］", "]")
                .replace("】", "]")
                .replace("﹞", "]")
                .replace("〕", "]")
                .replace("〗", "]")
                .replace("＿", "_")
                .replace("˜", "~")
                .replace("∼", "~")
                .replace("˜", "~")
                .replace("∼", "~")
                .replace("＋", "+")
                .replace("‹", "<")
                .replace("〈", "<")
                .replace("＜", "<")
                .replace("〉", ">")
                .replace("＞", ">")
                .replace("ａ", "a")
                .replace("ª", "a")
                .replace("á", "a")
                .replace("à", "a")
                .replace("ȧ", "a")
                .replace("â", "a")
                .replace("ä", "a")
                .replace("ǎ", "a")
                .replace("ă", "a")
                .replace("ā", "a")
                .replace("ã", "a")
                .replace("å", "a")
                .replace("ą", "a")
                .replace("ấ", "a")
                .replace("ầ", "a")
                .replace("ắ", "a")
                .replace("ằ", "a")
                .replace("ǻ", "a")
                .replace("ẫ", "a")
                .replace("ẵ", "a")
                .replace("ả", "a")
                .replace("ȁ", "a")
                .replace("ȃ", "a")
                .replace("ạ", "a")
                .replace("ậ", "a")
                .replace("ẚ", "a")
                .replace("ặ", "a")
                .replace("ɐ", "a")
                .replace("ɑ", "a")
                .replace("α", "a")
                .replace("ά", "a")
                .replace("ᾰ", "a")
                .replace("ᾶ", "a")
                .replace("а", "a")
                .replace("ӓ", "a")
                .replace("ӑ", "a")
                .replace("ｂ", "b")
                .replace("ß", "b")
                .replace("β", "b")
                .replace("в", "b")
                .replace("¢", "c")
                .replace("￠", "c")
                .replace("€", "c")
                .replace("ↅ", "c")
                .replace("ｃ", "c")
                .replace("ć", "c")
                .replace("ċ", "c")
                .replace("ĉ", "c")
                .replace("č", "c")
                .replace("ç", "c")
                .replace("ḉ", "c")
                .replace("с", "c")
                .replace("ҫ", "c")
                .replace("ｄ", "d")
                .replace("ḋ", "d")
                .replace("ď", "d")
                .replace("đ", "d")
                .replace("ʤ", "d")
                .replace("ɖ", "d")
                .replace("ｅ", "e")
                .replace("é", "e")
                .replace("è", "e")
                .replace("ė", "e")
                .replace("ê", "e")
                .replace("ë", "e")
                .replace("ě", "e")
                .replace("ĕ", "e")
                .replace("ē", "e")
                .replace("ẽ", "e")
                .replace("ę", "e")
                .replace("ȩ", "e")
                .replace("ế", "e")
                .replace("ề", "e")
                .replace("ḗ", "e")
                .replace("ễ", "e")
                .replace("ẻ", "e")
                .replace("ȅ", "e")
                .replace("ȇ", "e")
                .replace("ể", "e")
                .replace("ẹ", "e")
                .replace("ệ", "e")
                .replace("е", "e")
                .replace("ѐ", "e")
                .replace("ё", "e")
                .replace("ӗ", "e")
                .replace("є", "e")
                .replace("ｆ", "f")
                .replace("ｇ", "g")
                .replace("ǵ", "g")
                .replace("ġ", "g")
                .replace("ĝ", "g")
                .replace("ǧ", "g")
                .replace("ğ", "g")
                .replace("ḡ", "g")
                .replace("ģ", "g")
                .replace("ɡ", "g")
                .replace("ｈ", "h")
                .replace("ℎ", "h")
                .replace("ḧ", "h")
                .replace("ḩ", "h")
                .replace("ħ", "h")
                .replace("ḥ", "h")
                .replace("ℏ", "h")
                .replace("н", "h")
                .replace("ћ", "h")
                .replace("ｉ", "i")
                .replace("ɪ", "i")
                .replace("ı", "i")
                .replace("í", "i")
                .replace("ì", "i")
                .replace("î", "i")
                .replace("ï", "i")
                .replace("ǐ", "i")
                .replace("ĭ", "i")
                .replace("ī", "i")
                .replace("ĩ", "i")
                .replace("į", "i")
                .replace("ɨ", "i")
                .replace("ỉ", "i")
                .replace("ȋ", "i")
                .replace("ị", "i")
                .replace("ɩ", "i")
                .replace("і", "i")
                .replace("ї", "i")
                .replace("ا", "i")
                .replace("إ", "i")
                .replace("أ", "i")
                .replace("ĳ", "j")
                .replace("ｊ", "j")
                .replace("ĵ", "j")
                .replace("ǰ", "j")
                .replace("ј", "j")
                .replace("ｋ", "k")
                .replace("ḱ", "k")
                .replace("ķ", "k")
                .replace("ḵ", "k")
                .replace("ⓚ", "k")
                .replace("κ", "k")
                .replace("к", "k")
                .replace("ќ", "k")
                .replace("ｌ", "l")
                .replace("ℓ", "l")
                .replace("ĺ", "l")
                .replace("ŀ", "l")
                .replace("ľ", "l")
                .replace("ļ", "l")
                .replace("ƚ", "l")
                .replace("ł", "l")
                .replace("ᴌ", "l")
                .replace("ḽ", "l")
                .replace("ḻ", "l")
                .replace("ɬ", "l")
                .replace("ȴ", "l")
                .replace("ι", "l")
                .replace("ί", "l")
                .replace("ϊ", "l")
                .replace("ῖ", "l")
                .replace("ｍ", "m")
                .replace("ḿ", "m")
                .replace("м", "m")
                .replace("ｎ", "n")
                .replace("ℕ", "n")
                .replace("ń", "n")
                .replace("ǹ", "n")
                .replace("ṅ", "n")
                .replace("ň", "n")
                .replace("ñ", "n")
                .replace("ņ", "n")
                .replace("ṇ", "n")
                .replace("ṋ", "n")
                .replace("и", "n")
                .replace("й", "n")
                .replace("ٍ", "o")
                .replace("َ", "o")
                .replace("ُ", "o")
                .replace("ِ", "o")
                .replace("ّ", "o")
                .replace("ð", "o")
                .replace("ｏ", "o")
                .replace("º", "o")
                .replace("ℴ", "o")
                .replace("ᴓ", "o")
                .replace("ó", "o")
                .replace("ò", "o")
                .replace("ȯ", "o")
                .replace("ô", "o")
                .replace("ö", "o")
                .replace("ǒ", "o")
                .replace("ŏ", "o")
                .replace("ō", "o")
                .replace("õ", "o")
                .replace("ǫ", "o")
                .replace("ő", "o")
                .replace("ố", "o")
                .replace("ồ", "o")
                .replace("ɵ", "o")
                .replace("ø", "o")
                .replace("ṍ", "o")
                .replace("ỗ", "o")
                .replace("ǿ", "o")
                .replace("ỏ", "o")
                .replace("ȍ", "o")
                .replace("ȏ", "o")
                .replace("ơ", "o")
                .replace("ọ", "o")
                .replace("ớ", "o")
                .replace("ờ", "o")
                .replace("ộ", "o")
                .replace("ợ", "o")
                .replace("ο", "o")
                .replace("ό", "o")
                .replace("ὅ", "o")
                .replace("о", "o")
                .replace("ӧ", "o")
                .replace("ｐ", "p")
                .replace("ṕ", "p")
                .replace("ρ", "p")
                .replace("ϱ", "p")
                .replace("ῥ", "p")
                .replace("р", "p")
                .replace("ｑ", "q")
                .replace("ɣ", "r")
                .replace("ｒ", "r")
                .replace("ŕ", "r")
                .replace("ř", "r")
                .replace("ŗ", "r")
                .replace("ｓ", "s")
                .replace("ś", "s")
                .replace("ṡ", "s")
                .replace("ŝ", "s")
                .replace("š", "s")
                .replace("ş", "s")
                .replace("ʂ", "s")
                .replace("ṣ", "s")
                .replace("ș", "s")
                .replace("ｔ", "t")
                .replace("ẗ", "t")
                .replace("ť", "t")
                .replace("ţ", "t")
                .replace("ƫ", "t")
                .replace("ṭ", "t")
                .replace("ț", "t")
                .replace("τ", "t")
                .replace("т", "t")
                .replace("µ", "u")
                .replace("ｕ", "u")
                .replace("ú", "u")
                .replace("ù", "u")
                .replace("û", "u")
                .replace("ü", "u")
                .replace("ǔ", "u")
                .replace("ŭ", "u")
                .replace("ū", "u")
                .replace("ũ", "u")
                .replace("ů", "u")
                .replace("ų", "u")
                .replace("ű", "u")
                .replace("ʉ", "u")
                .replace("ǘ", "u")
                .replace("ǜ", "u")
                .replace("ǚ", "u")
                .replace("ǖ", "u")
                .replace("ủ", "u")
                .replace("ȕ", "u")
                .replace("ȗ", "u")
                .replace("ư", "u")
                .replace("ứ", "u")
                .replace("ừ", "u")
                .replace("ữ", "u")
                .replace("ự", "u")
                .replace("μ", "u")
                .replace("υ", "u")
                .replace("ύ", "u")
                .replace("ϋ", "u")
                .replace("ΰ", "u")
                .replace("ц", "u")
                .replace("ｖ", "v")
                .replace("ν", "v")
                .replace("ｗ", "w")
                .replace("ẃ", "w")
                .replace("ẁ", "w")
                .replace("ŵ", "w")
                .replace("ẅ", "w")
                .replace("ｘ", "x")
                .replace("х", "x")
                .replace("ӿ", "x")
                .replace("ｙ", "y")
                .replace("ý", "y")
                .replace("ỳ", "y")
                .replace("ŷ", "y")
                .replace("ÿ", "y")
                .replace("ỹ", "y")
                .replace("ẙ", "y")
                .replace("ỷ", "y")
                .replace("γ", "y")
                .replace("у", "y")
                .replace("ź", "z")
                .replace("ż", "z")
                .replace("ẑ", "z")
                .replace("ž", "z")
                .replace("ƶ", "z")
                .replace("·", " ")
                .replaceAll(" +", " ")
                .replaceAll(",+", ",")
                .replace(", ", ",")
                .replace(" ,", ",")
                .replace(",", " ")
                .replace(". ", "")
                .replace(" .", "")
                .replace(".", "")
                .replace("- ", "")
                .replace(" -", "")
                .replace("-", "")
                .replace(" ?", "")
                .replace("? ", "")
                .replace("?", "")
                .toLowerCase().replaceAll(" +", " ").trim();
        return str;
    }

    /**
     * @param str
     * @return
     */
    public static String reAuStand(String str) {

        str = preHandleReAuAuthor(str);
        //Liu Yinping; Liao Shijun; Li Zhibin
        //部分里面自带; 需要用自己的切割字符
        String res = "";
        if (str.contains(".;-;")) {
            res = str.replaceAll("  ", " ").replaceAll("\\?", "").replaceAll("？", "").replace(".;-;", "!@#").trim();

        } else if (str.contains(";-;")) {
            res = str.replaceAll("  ", " ").replaceAll("\\?", "").replaceAll("？", "").replace(";-;", "!@#").trim();

        } else if (str.contains(".; ")) {
            res = str.replaceAll("  ", " ").replaceAll("\\?", "").replaceAll("？", "").replace(".; ", "!@#");

        } else if (str.contains("; ")) {
            res = str.replaceAll("  ", " ").replaceAll("\\?", "").replaceAll("？", "").replace("; ", "!@#");

        }
        // ,不能處理否則人就拆開了
//        else if (str.contains(",")) {
//            res = str.replaceAll("  ", " ").replaceAll("\\?", "").replaceAll("？", "").replace(",", "!@#");
//
//        }
        else {
            res = str;
        }

        return res;
    }

    //预处理作者信息
    public static String preHandleReAuAuthor(String str) {

        //保留最原始de
        String ori = str;
        //处理作者
        try {
            String rex = "[A-Za-z0-9];-;[A-Za-z0-9].+";
            Matcher matcher = Pattern.compile(rex).matcher(str);
            while (matcher.find()) {
                String regexStr = matcher.group(0);
                str = str.replace(matcher.group(0), regexStr.replace(";-;", ";"));
            }
        } catch (Exception e) {

        }
        return str;
    }

    // 获取论文信息。得分的计算方法考虑了出版时间，影响因子，中科院的分区，被引次数等。其中，被引次数根据出版时间得到不等的系数，出版时间越老，系数越小，但只要有被引次数，最小的系数为1，没有被引次数的，均为0.25。只要2005年以来的数据。
    public void getArticleInfoPm(Entity entry, Integer nowYear, Map<Integer, SubjectDatabaseWord.ArticleInfo> allArticleInfoMap) {

//        int aId = OftenUtils.getIntField(entry, "article_id");
        // pm处理 pmid
        int aId = OftenUtils.getIntField(entry, "data_unique");
        int pubYear = OftenUtils.strToInteger(OftenUtils.getStrField(entry, "pub_year"));
        if (aId > 0 && pubYear > 0) {
            SubjectDatabaseWord.ArticleInfo articleInfo = new SubjectDatabaseWord.ArticleInfo();
            articleInfo.setAId(aId);
            articleInfo.setZkySmall(OftenUtils.strToList(OftenUtils.getStrField(entry, "zky_xiao_lei")));
            articleInfo.setBeiDaDaLei(OftenUtils.getStrField(entry, "beida_dalei"));
            articleInfo.setBeiDaXiaoLei(OftenUtils.getStrField(entry, "beida_xiao_lei"));
            articleInfo.setPmid(OftenUtils.strToInteger(OftenUtils.getStrField(entry, "data_unique")));
            articleInfo.setPubMedSubject(OftenUtils.strToList(OftenUtils.getStrField(entry, "pubmed_subject")));
            int jId = OftenUtils.getIntField(entry, "jour_id");
            articleInfo.setJid(jId);
            articleInfo.setEnKwMap(OftenUtils.strToMap(OftenUtils.getStrField(entry, "en_kw_map")));
            articleInfo.setCnKwList(OftenUtils.strToList(OftenUtils.getStrField(entry, "cn_kw_list")));
            int zhongHua = OftenUtils.getIntField(entry, "is_zhong_hua");
            int beiDa = OftenUtils.getIntField(entry, "is_beida");
            int tongJiYuan = OftenUtils.getIntField(entry, "is_tongjiyuan");
            int cscd = OftenUtils.getIntField(entry, "is_cscd");
            int zky = OftenUtils.getIntField(entry, "is_zky");
            int pubMed = OftenUtils.getIntField(entry, "is_pubmed");
            int sixJ = OftenUtils.getIntField(entry, "is_six_j");
            int cite = OftenUtils.getIntField(entry, "is_cite");
            articleInfo.setIsSixJ(sixJ);
            articleInfo.setIsZHua(zhongHua);
            articleInfo.setIsBeida(beiDa);
            articleInfo.setIsTongJiYuan(tongJiYuan);
            articleInfo.setIsCscd(cscd);
            articleInfo.setIsPubmed(pubMed);
            articleInfo.setIsCite(cite);
            articleInfo.setIsZky(zky);
            int zkyDaLeiInt = 6;
            int zky_dalei = OftenUtils.getIntField(entry, "zky_dalei");
            if (zky_dalei > 0) {
                zkyDaLeiInt = zky_dalei;
            } else {
                if ((zhongHua + beiDa + tongJiYuan + cscd + zky + pubMed + sixJ + cite) > 0) {
                    zkyDaLeiInt = 5;
                }
            }
            articleInfo.setZkyDaleiInt(zkyDaLeiInt);
            articleInfo.setZkySubject(OftenUtils.strToList(OftenUtils.getStrField(entry, "zky_subject")));

            articleInfo.setPubYear(pubYear);
            if (pubYear < 2010) {
                pubYear = 2010;
            }
            double pubTime = pubYear + PublicUtils.getDateScore(OftenUtils.getStrField(entry, "pub_date"));
            int tc = OftenUtils.getIntField(entry, "citation_num");
            articleInfo.setTimeCited(tc);
            double citeScore = OftenUtils.getDouField(entry, "cite_score");
            if (citeScore < 0.01) {
                citeScore = 0.01;
            }
            double score = OftenUtils.Arith.div((OftenUtils.Arith.div((pubTime - 2009), 11) * citeScore), zkyDaLeiInt);
            double ratio = 0.25; // 系数
            if (tc > 0) {
                int yearNum = nowYear - pubYear;
                if (yearNum < 2) {
                    ratio = OftenUtils.Arith.div(tc, 1);
                }
                if (yearNum == 2) {
                    ratio = OftenUtils.Arith.div(tc, 2);
                }
                if (yearNum == 3) {
                    ratio = OftenUtils.Arith.div(tc, 3);
                }
                if (yearNum == 4) {
                    ratio = OftenUtils.Arith.div(tc, 4);
                }
                if (yearNum == 5 || yearNum == 6) {
                    ratio = OftenUtils.Arith.div(tc, 5);
                }
                if (yearNum > 6 && yearNum < 10) {
                    ratio = OftenUtils.Arith.div(tc, 6);
                }
                if (yearNum > 9) {
                    ratio = OftenUtils.Arith.div(tc, 10);
                }
                if (ratio < 1.0) {
                    ratio = 1.0;
                }
            }
            score = score * ratio;
            articleInfo.setScore(score);

            Set<String> firstAuthSet = new HashSet<>();
            firstRealAuth(OftenUtils.getStrField(entry, "first_en_au"), firstAuthSet);
            firstRealAuth(OftenUtils.getStrField(entry, "first_cn_au"), firstAuthSet);
            articleInfo.setFirstAuthSet(firstAuthSet);

            Set<String> corrAuthSet = new HashSet<>();
            firstAuthUnit(OftenUtils.getStrField(entry, "first_corr"), corrAuthSet);
            firstAuthUnit(OftenUtils.getStrField(entry, "corr_auth"), corrAuthSet);
            articleInfo.setCorrAuthSet(corrAuthSet);

            articleInfo.setFundList(PublicUtils.getFundList(OftenUtils.getStrField(entry, "fund_list")));

            // 下面为因合并而新添加的字段：
            double zkyDaLeiDou = zky_dalei + 0.0;
            if (zkyDaLeiDou == 2.0) {
                zkyDaLeiDou = 0.5;
            }
            if (zkyDaLeiDou == 3.0) {
                zkyDaLeiDou = 0.33;
            }
            if (zkyDaLeiDou == 4.0) {
                zkyDaLeiDou = 0.25;
            }
            if (zkyDaLeiDou < 0.1) {
                if ((zhongHua + beiDa + tongJiYuan + cscd + zky + pubMed) > 0) {
                    zkyDaLeiDou = 0.2;
                }
            }
            articleInfo.setZkyDaLeiDou(zkyDaLeiDou);

            String unit = OftenUtils.getStrField(entry, "unit_list");
            if (SubjectDatabaseWord.isChina(unit)) {
                articleInfo.setIsChina(1);
            }
            List<String> unitList = OftenUtils.strToList(unit);
            articleInfo.setUnitList(unitList);
            articleInfo.setPubTime(pubTime);
            articleInfo.setEnAuthList(OftenUtils.strToList(OftenUtils.getStrField(entry, "en_auth_list")));
            articleInfo.setCnAuthList(OftenUtils.strToList(OftenUtils.getStrField(entry, "cn_auth_list")));
            articleInfo.setAltmetric(OftenUtils.getDouField(entry, "altmetric"));
            articleInfo.setScieIf(OftenUtils.getDouField(entry, "scie_if"));
            articleInfo.setCitationQuota(OftenUtils.getDouField(entry, "citation_quota"));
            articleInfo.setReferenceQuota(OftenUtils.getDouField(entry, "reference_quota"));
            articleInfo.setDeptList(PublicUtils.getDeptList(OftenUtils.getStrField(entry, "dept_list")));
            List<SubjectDatabaseWord.DataInfo> dataInfoList = JSONObject.parseArray(OftenUtils.getStrField(entry, "data_info"), SubjectDatabaseWord.DataInfo.class);
            articleInfo.setDataInfoList(dataInfoList);
            allArticleInfoMap.put(aId, articleInfo);
        }
    }

    // 以";"作为分隔点，获取第一作者，并对作者去乱字符，并进行去空格。
    public void firstAuth(String auth, Set<String> set) {
        if (auth.indexOf(";") > 1) {
            auth = auth.substring(0, auth.indexOf(";")).trim();
        }
        if (auth.length() > 1) {
            set.add(reName(auth));
        }
    }


}
